############################
##                       _oo0oo_
##                      o8888888o
##                      88" . "88
##                      (| -_- |)
##                      0\  =  /0
##                    ___/`---'\___
##                  .' \\|     |// '.
##                 / \\|||  :  |||// \
##                / _||||| -:- |||||- \
##               |   | \\\  - /// |   |
##               | \_|  ''\---/''  |_/ |
##               \  .-\__  '-'  ___/-. /
##             ___'. .'  /--.--\  `. .'___
##          ."" '<  `.___\_<|>_/___.' >' "".
##         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
##         \  \ `_.   \_ __\ /__ _/   .-` /  /
##     =====`-.____`.___ \_____/___.-`___.-'=====
##                       `=---='
##
##
##     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
##
##           佛祖保佑     永不宕机     永无BUG
##
##LastEditors: PartyParrot(__init__)
##Date: 2022-06-11 12:52:09
##LastEditTime: 2022-06-12 19:30:54
##FilePath: EasyLexer.py
##Author: PartyParrot(__init__)
##Description: 
############################

# -*- coding:utf-8 -*-
from .EasyToken import *
from .EasyErrors import *
from .EasyPosition import *

class Lexer:
    # Lexer，即词法分析器或分词器（Tokenizer），作用是将一串命令以 Token 为单位分析，如：1 + 2 就可分析为 [INT:1, PLUS, 2]。
    def __init__(self, file_name, text):
        """\
        text: 解析文字
        file_name: 文件名
        """
        # 文件名
        self.file_name = file_name
        # 代码
        self.text = text
        # pos: 光标
        self.pos = Position(-1, 0, -1, file_name, text)
        # current_char: 当前字符
        self.current_char = None
        self.advance()

    # 预读取字符
    def advance(self):
        # 光标 + 1
        self.pos.advance(self.current_char)
        # 获取当前字符
        self.current_char = self.text[self.pos.index] if self.pos.index < len(self.text) else None

    # 解析字符串
    def make_tokens(self):
        tokens = []

        # 如果 self.current_char 不为 None 就循环
        while self.current_char != None:
            # 如果 self.current_char 是空格、制表符则预读取下一个字符
            if self.current_char in ' \t':
                self.advance()
            # 如果 self.current_char 是数字，调用 make_number 方法
            elif self.current_char in DIGITS:
                tokens.append(self.make_number())
                # self.advance()
            # 如果 self.current_char 是 + ，则在加入Tokens列表后预读取
            elif self.current_char == '+':
                tokens.append(Token(PLUS))
                self.advance()
            # 如果 self.current_char 是 - ，则在加入Tokens列表后预读取
            elif self.current_char == '-':
                tokens.append(Token(MINUS))
                self.advance()
            # 如果 self.current_char 是 * ，则在加入Tokens列表后预读取
            elif self.current_char == '*':
                tokens.append(Token(MUL))
                self.advance()
            # 如果 self.current_char 是 / ，则在加入Tokens列表后预读取
            elif self.current_char == '/':
                tokens.append(Token(DIV))
                self.advance()
            # 如果 self.current_char 是 ( ，则在加入Tokens列表后预读取
            elif self.current_char == '(':
                tokens.append(Token(LPAREN))
                self.advance()
            # 如果 self.current_char 是 ) ，则在加入Tokens列表后预读取
            elif self.current_char == ')':
                tokens.append(Token(RPAREN))
                self.advance()
            else:
                # 锁定错误开始位置
                pos_start = self.pos.copy()
                # 确定 char
                char = self.current_char
                self.advance()
                return [], IllegalCharError(pos_start, self.pos, f"'{char}'")

        return tokens, None

    def make_number(self):
        num_str = ''
        dot_count = 0
        
        # 如果 self.current_char 不等于 None 且在 '0123456789.' 中则开始循环
        while self.current_char != None and self.current_char in DIGITS + '.':
            # 如果 self.current_char 是 . 则 dot_count + 1
            if self.current_char == '.':
                if dot_count == 1:
                    break
                dot_count += 1
                num_str += '.'
            else:
                num_str += self.current_char
            self.advance()
        
        if dot_count == 0:
            return Token(INT, int(num_str))
        else:
            return Token(FLOAT, float(num_str))